package com.autumn.platform.auth.web;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;

import com.autumn.platform.auth.core.access.IAccessController;
import com.autumn.platform.auth.core.access.IPermission;
import com.autumn.platform.auth.core.access.IPermissionMapping;
import com.autumn.platform.core.context.reqeust.IRequest;
import com.autumn.platform.core.context.reqeust.RequestContextHolder;
import com.autumn.platform.core.context.response.IResponse;

public class AuthHandlerMapping extends AbstractHandlerMapping {

    /**
     * 认证信息存储在请求中的属性名称
     */
    private static final String AUTHORIZATION_IN_REQUEST_ATTR_NAME = AuthHandlerMapping.class.getName() + ".AUTHORIZATION_IN_REQUEST_ATTR_NAME";

    /**
     * 请求权限存储在请求中的属性名称
     */
    private static final String PERMISSION_IN_REQUEST_ATTR_NAME = AuthHandlerMapping.class.getName() + ".PERMISSION_IN_REQUEST_ATTR_NAME";

    /**
     * 请求权限映射
     */
    @Autowired(required = false)
    private IPermissionMapping permissionMapping;

    /**
     * 权限认证器
     */
    @Autowired(required = false)
    private IAccessController accessController;

    @Autowired(required = false)
    private HandlerMappingIntrospector introspector;

    private static Method method;

    static {
        try {
            method = AuthHandlerMapping.class.getDeclaredMethod("doHandlerAuthorizationStatus", HttpServletRequest.class);
        } catch (Exception e) {
        }
    }

    /**
     * 构造函数，设置高优先级
     */
    public AuthHandlerMapping() {
        super();
        super.setOrder(HIGHEST_PRECEDENCE);
    }

    /**
     * 处理认证失败的请求
     * 
     * @param request
     * @return
     * @throws Exception
     */
    @ResponseBody
    public Object doHandlerAuthorizationStatus(HttpServletRequest request) throws Exception {
        IRequest req = RequestContextHolder.getRequest();
        return getAuthorizationStatus(req);
    }

    /**
     * 获取处理器
     */
    @Override
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        IRequest req = RequestContextHolder.getRequest();
        if (null != req && isHandlrMethodRequest(request)) {
            IResponse response = getAuthorizationStatus(req);
            if (null != response && !response.isSuccess()) {
                return new HandlerMethod(this, method);
            }
        }
        return null;
    }

    private boolean isHandlrMethodRequest(HttpServletRequest request) throws Exception {
        if (null != introspector) {
            for (HandlerMapping mapping : introspector.getHandlerMappings()) {
                if (!(mapping instanceof AuthHandlerMapping)) {
                    HandlerExecutionChain chain = mapping.getHandler(request);
                    if (null != chain && chain.getHandler() instanceof HandlerMethod) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 获取请求对应的权限
     * 
     * @return
     */
    private IPermission getRequestPermission(IRequest request) {
        Object attribute = getRequestAttribute(PERMISSION_IN_REQUEST_ATTR_NAME);
        if (attribute instanceof IPermission) {
            return (IPermission) attribute;
        } else if (null != getRequestAttribute(PERMISSION_IN_REQUEST_ATTR_NAME + ".FLAG")) {
            return null;
        } else if (null != permissionMapping) {
            setRequestAttribute(PERMISSION_IN_REQUEST_ATTR_NAME + ".FLAG", new Object());
            if (null != request) {
                IPermission permission = permissionMapping.lookup(request);
                setRequestAttribute(PERMISSION_IN_REQUEST_ATTR_NAME, permission);
                return permission;
            }
        }
        return null;
    }

    /**
     * 获取请求对应的权限认证
     * 
     * @return
     * @throws Exception
     */
    private IResponse getAuthorizationStatus(IRequest request) throws Exception {
        Object attribute = getRequestAttribute(AUTHORIZATION_IN_REQUEST_ATTR_NAME);
        if (attribute instanceof IResponse) {
            return (IResponse) attribute;
        } else if (null != getRequestAttribute(AUTHORIZATION_IN_REQUEST_ATTR_NAME + ".FLAG")) {
            return null;
        } else if (null != accessController) {
            setRequestAttribute(AUTHORIZATION_IN_REQUEST_ATTR_NAME + ".FLAG", new Object());
            IPermission permission = this.getRequestPermission(request);
            IResponse info = accessController.isPermitted(permission);
            setRequestAttribute(AUTHORIZATION_IN_REQUEST_ATTR_NAME, info);
            return info;
        }
        return null;
    }

    private static Object getRequestAttribute(String name) {
        return org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes().getAttribute(name, RequestAttributes.SCOPE_REQUEST);
    }

    private static void setRequestAttribute(String name, Object value) {
        org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes().setAttribute(name, value, RequestAttributes.SCOPE_REQUEST);
    }
}
